/**
* @class Provides the core bizproc behavior, intended to be overriden by child bizproc classes.
*
* The details for child bizproc inheritence in javascript is a bit different than other patterns
* for inheritence.  A bizproc facatory method will create an instance of this class, passing in the
* child class as a parameter.  The BizProc constructor will set itself up and then blend in the child
* methods and data elements using $.extend.
<pre>
&lt;div class="ksg-bizproc ksg-bizproc-articleManagement" id="art1" 
	data-options='{"editModeSessionKey":"GlobalEdit"}'
	data-art-options='{"id":"", "details": "basicDetails", "includeCounts": true, "entireTree": true}'&gt;
&lt;/div&gt;		
</pre>
*
* @Depends ksg.base.ui.js
* @meta-type abstract base class
* @importance high

* @param {String} id The unique identifier relative to the overall page hosting this bizproc.
* @param {Object} dataParams the various parameters supplied to create the bizproc.
* <p>When this is provided by the ksg-bizproc class being attached to a DOM element, this
* is created from all the data-[name] elements defined on the DOM element.</p>
* @param {Object} childBizProc A plain object that contains methods and properties to be blended into
* the new bizproc object being created.
*/
ksg.ui.BizProc = function(id, dataParams, childBizProc) {
	this.id = id;
	this.options = dataParams.options;
	this.parentBizProcs = dataParams["parent-bizprocs"];
	
	/**
	* Keeps track of how far this bizproc has gotten in getting its initial data shown from since it was first created.
	* Values: 0=no init. 1=startedGettingData. 2=Done getting initial data.
	* @type integer
	* @private
	*/
	this.initState = 0;
	
	//#Paging support ---
	/**
	* Keeps track of the current page when the bizobj list is being paged by the list displayers.
	* @type integer
	* @private
	*/
	this.currentPage = 0;
	//#
	
	/**
	* Flag to track if we have attempted to retrieve the bizobj list from the source.
	* @type boolean
	* @private
	*/
	this.retrievedBizObjList = false;
	/**
	* Flag to track if we have attempted to retrieve the current bizobj details from the source.
	* @type boolean
	* @private
	*/
	this.retrievedCurrentBizObj	= false;
	
	/**
	* When the add bizobj action is triggered, a new instances of the bizobj type is created and
	* put here while it is being edited.  This helps to indicate to other logic that we are in add mode.
	* @type ksg.bizobj.IBizObj
	* @private
	*/
	this.inProgressAddBizObj = null;
	
	/**
	* The id of the current bizobj.
	* @type Object
	* @private
	*/
	this.currentBizObjId = null;
	
	/**
	* The fully populated selected bizobj.  This is typically set by calling the getBizObjBizRule, but
	* could also come from the bizobj list directly if getBizObjBizRule is not set.
	* @type ksg.bizobj.IBizObj
	* @private
	*/
	this.currentBizObj = null;
	
	/**
	* Used to keep track of the main list of bizobjs as well as current index for the selected bizobj.
	* When the move next/prev first/last actions are used, this is the data member that keeps track of that state.
	* @type ksg.bizobj.BizObjCursor
	* @private
	*/
	this.bizObjCur = null;
	
	/**
	* The collection of bizrule names used by the bizproc to interact with the middle tier.
	* The rules defined at this level are those know to the base BizProc class, but
	* child classes can add other bizrule names to call in here.
	* <ul>
	*	<li>getBizObjListBizRule - the bizrule to get the list of bizobjs being used</li>
	*	<li>getBizObjBizRule - the bizrule to get the details of one bizobj</li>
	*	<li>getMasterBizObjListBizRule - the bizrule to get the master list of all bizobjs related to this bizproc.</li>
	* 	<li>updateBizRule - the bizrule to update a single bizobj</li>
	*	<li>deleteBizRule - the bizrule to delete a single bizobj</li>
	* </ul>
	*
	* @type Map<String, String>
	* @private
	*/
	this.bizRules = {
		/**
		* A bizrule that takes an options Map and returns an IBizObjList
		*/
		getBizObjListBizRule: null,
		getBizObjBizRule: null,
		getMasterBizObjListBizRule: null,
		
		updateBizRule: null,
		deleteBizRule: null,		
		bulkUpdateBizRule: null		
	};
	
	var self = this;
	this.actions = {};
	
	this._addAction(new ksg.ui.Action("SwitchEdit", function() {self._switchEditMode();}));
	
	this._addAction(new ksg.ui.Action("AddBizObj", function() {self._addBizObj();}));
	this._addAction(new ksg.ui.Action("UpdateBizObj", function() {self._updateBizObj();}));
	this._addAction(new ksg.ui.Action("DeleteBizObj", function() {self._deleteCurrentBizObj();}));
	this._addAction(new ksg.ui.Action("CancelEdits", function() {self._cancelEdits();}));
	
	//#Indexing Support ---
	this._addAction(new ksg.ui.Action("MoveFirst", function() {self._moveFirst();}));
	this._addAction(new ksg.ui.Action("MovePrev", function() {self._movePrev();}));
	this._addAction(new ksg.ui.Action("MoveNext", function() {self._moveNext();}));
	this._addAction(new ksg.ui.Action("MoveLast", function() {self._moveLast();}));
	//#
	
	//Blend in the child bizproc methods and values into this.
	$.extend(true, this, childBizProc); 
	
	this._setupActions();
	
	ksg.App.bizProcMgr.registerBizProc(this);
}

//The base bizproc prototype methods.
ksg.ui.BizProc.prototype = {	
	/**
	* If the main bizobj's keyvalue field name is not the default value set here, the
	* child bizproc should override this with the proper field name to be used.
	* @type String
	*/
	_keyName: "id" ,
	/**
	* Returns the key name of the bizobj used for its unique id.
	* @returns {String}
	*/
	getKeyName: function() {return this._keyName;},

	/**
	* The main entrypoint for getting the bizproc to retrieve its data (if needed) and show it in its list and 
	* detail displays.  This method is typically called by the bizproc manager.
	*/
	showData: function() {
		var self = this;
		var listDisplays = this._getListDisplays();
		var bizObjs = null;
		
		//This is only relevant during initialization.  Once initState reaches two and further calls to show data happen, nothing changes for this variable.
		//Helps the bizproc manager know if a given bizproc has been initialized yet.
		if(self.initState==0)
			self.initState = 1;
		
		//Get the list displays and have them show the bizobj list retrieved from getSourceBizObjs.
		if(listDisplays.length > 0) {
			self.getSourceBizObjs(function(bizObjs) {
				var cur = self._setupCursor(bizObjs, listDisplays);
				
				var editPriv = self.CanEdit() ? self.CurrentEditPrivilege() :
								self.CurrentEditPrivilege() == ksg.security.Privileges.None ? 
								ksg.security.Privileges.None : ksg.security.Privileges.ReadOnly;
				for(var i in listDisplays) {
					var listDisp = listDisplays[i];
					listDisp.setEditPrivilege(editPriv);	
					self._showBizObjListInDisplay(listDisp, cur);	
				}
				self._showBizObjDetails();
			});
		}
		else
			this._showBizObjDetails();
	},

	/**
	* Given a relationship id, will search all of its parent bizprocs looking for a relationship
	* that matches the provided id and if found returns the value from the relationship.
	* @param {String} relationshipId the unique identifier used to define the relationship between this bizproc
	* and a parent bizproc.
	* @returns {Object} the value from the parent bizproc or null if the parent could not be found or 
	* hasnt had it data setup yet.
	*/
	_getParentBizProcValue: function(relationshipId) {
		var parents = this.parentBizProcs;
		if(parents)
			for(var i in parents) {
				if(parents[i].id == relationshipId) {
					var bizProc = ksg.App.bizProcMgr.getBizProc(parents[i].bizProcId);
					if(bizProc) {
						var parentBizObj = bizProc.getCurrentBizObj();
						if(parentBizObj != null)
							return parentBizObj[parents[i].fieldName];
					}
				}
			}
	},
	
	/**
	* A bizproc is not ready to get its own data if it has parent bizprocs that have not gotten their
	* data yet.  This method will check to see if it has not yet been initialized and also if all its parents
	* have gotten their data yet.
	*
	* The only way this method will return true is if this object has not been initialized, and all parent
	* bizprocs have already been initialized.
	*/
	isReadyToGetInitialData: function() {
		//starts at 2 to assume all parent bizprocs have their data already.
		//IF a parent has less than a 2 for their initState, the readyState is adjusted down.
		var readyState = 2;
		var parents = this.parentBizProcs;
		if(parents)
			for(var i in parents) {
				var parent = ksg.App.bizProcMgr.getBizProc(parents[i].bizProcId);
				if(parent.initState < readyState) {
					readyState = parent.initState;
					break;
				}
			}
				
		return this.initState == 0 && readyState == 2;
	},
	
	/**
	* Primarily called by showData, Sets up a bizobjlist cursor based on the bizObjs provided.
	* Positions cursor to first bizobj that should be displayed in first list.
	*
	* Expects bizObjs to represent the full list of bizobjs, not just a single page of bizObjs.
	* Also sets up the pager controls if there are any, which indicates paging is being used.
	* @param {ksg.bizobj.IBizObjList} bizObjs the bizobjs to use for the cursor
	* @param {ksg.ui.IBizObjListDisplay[]} listDisplays The array of bizobj list displays that will be used to
	* calculate the page size with.
	*/
	_setupCursor: function(bizObjs, listDisplays) {
		var self = this;
		var cur = new ksg.bizobj.BizObjCursor(bizObjs);
		
		//#Paging support ---
		var pagers = self._getPagerDisplays();
		if(pagers) {
			var pagesize = self._calculateMaxBizObjsShown(listDisplays);
			for(var pager in pagers)
				pager.setupPagination(bizObjs.length, pagesize, self.currentPage);

			cur.moveTo(self.currentPage * pagesize);
		}
		//#
		
		return cur;
	},
	
	/**
	* Called during the showData process, this first starts the async process of getting the current
	* bizobj details and then showing the bizobj in the bizproc detail displays.
	*/
	_showBizObjDetails: function() {
		var self = this;

		var detailDisplays = self._getDetailDisplays();
		self.getCurrentBizObj(function(bizObj) {
			if(bizObj == null)
				bizObj = self.createNewBizObj();
				
			//This if statement is designed to prevent the display of a bizobj from being different from that
			//set as the currentBizObjId.  This can happen when the user is rapidly moving through the list of
			//bizobjs.  Getting the details for a bizobj is async, and multiple requests for setting the current
			//bizobj can cause many requests to be made and come in async.
			if(bizObj[self._keyName] == self.currentBizObjId)
				for(var i in detailDisplays)
					self._showBizObjInDisplay(detailDisplays[i], bizObj);
		});
		
		self._updateActionState();
	},
	
	/**
	* Returns the current state of if the user is able to edit at this moment.  This is not the same as asking
	* if the user is authorized to edit.  If the bizproc is a part of the global edit mode and that edit mode is off, 
	* then the user cannot edit until edit mode is on again.
	*
	* @returns {boolean}
	*/
	CanEdit: function() {
		var e = this.CurrentEditPrivilege() >= ksg.security.Privileges.EditOnly;
		if (e && this.UsingEditModeForEdits())
			e = ksg.App.SessionData()[this.options.editModeSessionKey]==true;
		return e;		
	},
	
	/**
	* The edit privilege of the user at the time. 
	* Child bizproc should override this method to calculate the privilege based on currentUser
	* and what security app function the bizproc wants to use for its security access.
	* @returns {ksg.security.Privileges} The security privilege the bizproc is using to determin its behavior.
	*/
	CurrentEditPrivilege: function() {
		return ksg.security.Privileges.None;
	},
	
	/**
	* Checks to see if the editModeSessionKey option is set.
	* @returns {boolean} True if the bizproc is configured with a editModeSessionKey
	*/
	UsingEditModeForEdits: function() {
		return this.options.editModeSessionKey && this.options.editModeSessionKey.length > 0;
	},
	
	/**
	* Not implemented yet, but should be.
	* @returns {ksg.ui.MasterDataOption}
	*/
	MasterDataOption: function() {
	},
		
	/**
	* When something happens that invalidates the data held by the bizproc, this will 
	* clear out the cached data so that when calls to ksg.ui.BizProc.getCurrentBizObj and
	* ksg.ui.BizProc.getSourceBizObjs happen again, they will see there is no cached data
	* and retrieve the bizobj list or detailed bizobj again when its needed.
	* @param {Boolean} clearBizObj set to true if the current bizobj should be cleared out.
	* @param {Boolean} clearBizObjList set to true if the source bizobj list should be cleared out.
	* @param {Boolean} includeCurrentBizObjId set to true if the currently selected bizobj id should
	* also be cleared out, causing the bizproc to have to calculate what the selected bizobj should
	* be the next time it's showData method is called.
	*/
	clearData: function(clearBizObj, clearBizObjList, includeCurrentBizObjId) {
		if(clearBizObj == true) {
			if(includeCurrentBizObjId != false)
				this.currentBizObjId = null;
			this.currentBizObj = null;
			this.retrievedCurrentBizObj = false;
		}
		if(clearBizObjList == true) {
			this.bizObjCur = null;
			this.retrievedBizObjList = false;
		}
	},
	
	/**
	* Typically called by the bizproc's bizObjList displays when a user
	* selects a bizobj in its display, but can also be used by any javascript that has a valid
	* id to set as the current selected bizobj.
	* @param {Object} bizObjId The unique identifier to use for the current bizobj
	* @param {Boolean} dontSetIndex optional - if false will not try to set the index from the given id.
	* This is provided when the cursor is being moved and is already set.
	*/
	selectBizObj: function(bizObjId, dontSetIndex) {
		var self = this;
		ksg.App.bizProcMgr.bizObjSelected(self, bizObjId, function() {
			self.clearData(true,false);
			self._setSelectedBizObjId(bizObjId);
			
			//#Indexing Support ---
			if(dontSetIndex != true) 
				self._setIndexFromBizObjId(bizObjId);
			//#
			
			self._showBizObjDetails();		
		});
	},
	
	/**
	* Iterates through each of associated bizobj list displays and asks it to try and select the given
	* id.  This is an internal helper method intended to make sure the list displays are showing the selected
	* bizobj, it is not intended to be the primary method for selecting a bizobj based on its id.
	* @param {Object} bizObjId the unique identifier of the bizobj that is to be setup as selected for.
	*/
	_setSelectedBizObjId: function(bizObjId) {
		this.currentBizObjId = bizObjId;
		var listDisplays = this._getListDisplays();
		if(listDisplays)
			for(var i in listDisplays)
				listDisplays[i].setSelectedBizObjKeyValue(bizObjId);
	},
	
	//#Indexing Support ---
	/**
	* Maintains the current selected index when the current bizobj is changed to some 
	* random location.  This helps to ensure that the move next/prev actions have their state
	* managed properly.  If someone clicks on the last item in the bizobj list, then the move next
	* action should be disabled.  This method does not manage the action state, it only moves
	* the internal ksg.bizobj.BizObjCursor object position.
	* @param {Object} bizObjId the unique identifier for the bizobj that the index should be set with.
	*/
	_setIndexFromBizObjId: function(bizObjId) {
		if(this.bizObjCur) {
			var bizObjs = this.bizObjCur.bizObjs;
			for(var i = 0; i < bizObjs.length; i++)
				if(bizObjs[i][this._keyName] == bizObjId) {
					this.bizObjCur.moveTo(i);
					return;
				}
		}
	},
	//#
	
	/**
	* Called internally when showing the bizobj list in its views, this method will simply
	* tell the display to show the data.
	* This is a good method to override in a child bizproc if you need to change the way in which
	* data is driven into a list display.
	* @param {ksg.ui.IBizObjListDisplay} listDisp The bizobj list display to show the list in.
	* @param {ksg.bizobj.BizObjCursor} cur The bizobj list cursor to use.
	*/
	_showBizObjListInDisplay: function(listDisp, cur) {
		if (listDisp.DrivenByBizProc())
		{
			listDisp.setSelectedBizObjKeyValue(this.getCurrentBizObjKeyValue());
			listDisp.showBizObjs(this, cur);
		}
	},
		
	/**
	* Calculates what the current bizobj key value is, which can be somewhat involved to come up with, 
	* especially if the user has yet to actually select a current bizobj or if there are no bizobjs in the list.
	* @returns {Object} The current bizobj id value or null if there is no current bizobj.
	*/
	getCurrentBizObjKeyValue: function() {
		var bizObjId = this.currentBizObjId;
		var bizObj = this.currentBizObj;
		if(bizObj)
			bizObjId = bizObj[this._keyName];
			
		if(!(bizObjId)) {
			var bizObjs = this.getSourceBizObjs();
			if (this.getCanDefaultToFirstInList() && bizObjs && bizObjs.length) {
				bizObjId = bizObjs[0][this._keyName];
				//#Indexing Support ---
				this.bizObjCur.moveTo(0);
				//#
			}
		}
		
		if(!(bizObjId)) {
			//TODO: check list display to see if they have current id from having content
			//embedded in them.  There is a chance that there was no bizobj list retrieved
			//because the bizobj list displays are prepopulated with content when the page was
			//rendered in the server.  If we need to know the "current bizobj id" and yet we dont
			//have it set from one being selected, we would need to ask the first bizobj list display
			//what their first bizobj's id value is.
		}
		
		if(bizObjId)
			this._setSelectedBizObjId(bizObjId);
		
		return bizObjId;
	},
	
	/**
	* Will get the current list of bizobjs if cached, or if passed a function for onSuccess,
	* this will call _getBizObjs to kick of the bizrule call to get the bizobj list.
	* @param {function} onSuccess optional - The handler to use if the bizrule has to be called
	* to get the bizobj list.  This will always be called if provided, even if the bizobj list
	* is already in memory.
	* @returns {ksg.bizobj.IBizObjList} If the bizobj list isnt cached, this will return null.
	*/
	getSourceBizObjs: function(onSuccess) {
		var self = this;
		var bizObjs = self.bizObjCur?self.bizObjCur.bizObjs:null;
		if(!(bizObjs) && onSuccess)
			self._getBizObjs(onSuccess);
		else if(onSuccess)
			onSuccess(bizObjs);		
		return bizObjs;
	},
	
	/**
	* This is an important method for child bizprocs to override in order to create any custom Action objects
	* it may need when first being created.
	* This method has no implementation in ksg.ui.BizProc, but is called for the child bizproc to setup
	* custom actions.  If you have no custom Actions for the child BizProc, you dont need to override this method.
	*/
	_setupActions: function() {
	//Intentionally left blank for child bizproc to override.
	},
	
	/**
	* Adds the given action into the collection of actions used by the bizproc.
	* @param {ksg.ui.Action} action The action to add.
	*/
	_addAction: function(action) {
		this.actions[action.id.toLowerCase()] = action;
	},
	
	/**
	* Access to a given action based on its id.
	* @param {String} actionId the id of the action to get
	* @returns {ksg.ui.Action} The Action that matches the id or null if no match found.
	*/
	getAction: function(actionId) {
		return this.actions[actionId.toLowerCase()];
	},
		
	/**
	* Updates the state and availability of the bizproc's actions.  This method is called at various points
	* during in the bizproc processing, which drive action trigger widgets (such as if a given action is available for 
	* the user at the moment).
	* It is typical for a child bizproc to override this method if they have custom Actions to manage, or if the 
	* standard way in which the standard Actions are managed needs to be changed.
	*/
	_updateActionState: function() {
		var curPriv = this.CurrentEditPrivilege();
		var action = null;
		var isNew = this.inProgressAddBizObj != null;
		
		if(action = this.getAction("ClearFilterSort"))
			action.availability = FilterSortCriteria == null ? ksg.ui.Availability.None : ksg.ui.Availability.Enabled;

		if(action = this.getAction("SwitchEdit"))
			action.availability =
				curPriv >= ksg.security.Privileges.EditOnly ? ksg.ui.Availability.Enabled:ksg.ui.Availability.None;
				
		if(action = this.getAction("MasterDataOption"))
			action.availability = (this.MasterDataOption() > ksg.ui.MasterDataOption.None) ? ksg.ui.Availability.Enabled : ksg.ui.Availability.None;
			
		if (this.CanEdit()) {

			if(action = this.getAction("DeleteBizObj"))
				action.availability =
				(isNew || curPriv == ksg.security.Privileges.None) ? ksg.ui.Availability.None :
				(curPriv == ksg.security.Privileges.Delete) ? ksg.ui.Availability.Enabled : ksg.ui.Availability.Disabled;
				
			if(action = this.getAction("AddBizObj"))
				action.availability =
				(isNew || curPriv == ksg.security.Privileges.None) ? ksg.ui.Availability.None :
				(curPriv == ksg.security.Privileges.AddOnly || curPriv >= ksg.security.Privileges.Add) ? ksg.ui.Availability.Enabled : ksg.ui.Availability.Disabled;
				
			if(action = this.getAction("CancelEdits"))
				action.availability = isNew ? ksg.ui.Availability.Enabled : ksg.ui.Availability.None;

			if(action = this.getAction("UpdateBizObj"))
				action.availability =
				(curPriv == ksg.security.Privileges.None) ? ksg.ui.Availability.None :
				(curPriv >= ksg.security.Privileges.AddOnly) ? ksg.ui.Availability.Enabled : ActionAvailability.Disabled;
		}
		else {
			if(action = this.getAction("DeleteBizObj"))
				action.availability = ksg.ui.Availability.None;
			if(action =this.getAction("AddBizObj"))
				action.availability = ksg.ui.Availability.None;
			if(action = this.getAction("UpdateBizObj"))
				action.availability = ksg.ui.Availability.None;
			if(action = this.getAction("CancelEdits"))
				action.availability = ksg.ui.Availability.None;
		}
		
		//#Indexing Support ---
		if (this.retrievedBizObjList) {
			var cur = this.bizObjCur;
			var couldBeEnabled = cur.hasMoreThanOne() && !isNew;
			if(action = this.getAction("MoveToFirst")) 
				action.availability = couldBeEnabled ? (cur.isBOF() ? ksg.ui.Availability.Disabled : ksg.ui.Availability.Enabled) : ksg.ui.Availability.None;
			if(action = this.getAction("MoveToLast"))
				action.availability = couldBeEnabled ? (cur.isEOF() ? ksg.ui.Availability.Disabled : ksg.ui.Availability.Enabled) : ksg.ui.Availability.None;
			if(action = this.getAction("MoveNext"))
				action.availability = couldBeEnabled ? (cur.isEOF() ? ksg.ui.Availability.Disabled : ksg.ui.Availability.Enabled) : ksg.ui.Availability.None;
			if(action = this.getAction("MovePrev"))
				action.availability = couldBeEnabled ? (cur.isBOF() ? ksg.ui.Availability.Disabled : ksg.ui.Availability.Enabled) : ksg.ui.Availability.None;
		}
		//#
		
		//Give child bizprocs a chance to manage any additional action states.
		this._updateAdditionalActionStates();
		
		//After setting up the state of our actions, we need to tell the action triggers to refresh their state.
		var actionTriggers = ksg.App.bizProcMgr.getBizProcWidgets(this.id, ksg.ui.BizProcWidgetType.ActionTrigger);
		for(var i in actionTriggers) {
			actionTriggers[i].setupStateFromActions();
		}
	},
	
	/**
	* A child bizproc should override this method if it just wants to manage the state of additional actions they manage,
	* or even want to change the state of the standard actions after they have had their state updated by the base bizproc.
	*/
	_updateAdditionalActionStates: function() {
		//Intentionally left blank.  This method is specifically for child bizprocs to override if needed.
	},
	
	/**
	* Given a bizobj and a detailDisplay, this method will setup the detailDisplay to be in the proper edit mode
	* and then tell it to display the given bizObj.
	* This is a good method for a child bizproc to override to add more behavior for when a bizobj is shown in a given display
	* or to change the way the bizobj is shown.
	* @param {ksg.ui.IBizObjDisplay} detailDisplay the display to show the bizobj in
	* @param {ksg.bizobj.IBizObj} bizObj the bizobj that will be used.
	*/
	_showBizObjInDisplay: function(detailDisplay, bizObj) {
		var currentEditPrivilege = this.CurrentEditPrivilege();
		detailDisplay.setEditPrivilege(this.CanEdit() ? currentEditPrivilege :
			currentEditPrivilege == ksg.security.Privileges.None ? ksg.security.Privileges.None : ksg.security.Privileges.ReadOnly);
			
		detailDisplay.displayBizObj(bizObj);
	},

	/**
	* Given the list of bizobj list displays, this method calculates the max number of bizobjs that are
	* going to be shown.
	* This is done by checking the max number of items each bizobj list display is setup to use and adding up 
	* that total.  If there are pager displays, this number is used to control how many pages of data there are as
	* this becomes the "page size" for the pager displays.
	* @param {ksg.ui.IBizObjListDisplay[]} listDisplays array of bizobj list displays being used by this bizproc. 
	* @returns {integer} -1 if all bizobjs will be shown, or the number of bizobjs shown.
	*/
	_calculateMaxBizObjsShown: function(listDisplays) {
		var numPerPage = 0;
		for (var i in listDisplays)	{
			try {
				var num = new Number(listDisplays[i].MaxElements());
				numPerPage += num;
			}
			catch(e) {
			}
		}
		return numPerPage;
	},
	
	/**
	* Calls ksg.App.bizProcMgr to find the child bizobj list displays for this bizproc.
	* The child bizobj list displays for a bizproc are never cached in the object.  Everytime
	* this method is called, the bizProcMgr is asked to create this list.
	*/
	_getListDisplays: function() {
		return ksg.App.bizProcMgr.getBizProcWidgets(this.id, ksg.ui.BizProcWidgetType.List);
	},

	/**
	* Calls ksg.App.bizProcMgr to find the child bizobj detaild displays for this bizproc.
	* The child bizobj detail displays for a bizproc are never cached in the object.  Everytime
	* this method is called, the bizProcMgr is asked to create this list.
	*/
	_getDetailDisplays: function() {
		return ksg.App.bizProcMgr.getBizProcWidgets(this.id, ksg.ui.BizProcWidgetType.Disp);
	},
	
	/**
	* If this bizproc has a complete dependency on another bizproc for its data, it wont use bizrules
	* to get its bizobj list
	*/
	_getCompletlyDependentParent: function() {
		return null;
	},
	
	//#Paging support ---
	/**
	* Calls ksg.App.bizProcMgr to find the child paging displays for this bizproc.
	* The pager displays for a bizproc are never cached in this object.  Everytime
	* this method is called, the bizProcMgr is asked to create the list.
	*/
	_getPagerDisplays: function() {
		return ksg.App.bizProcMgr.getBizProcWidgets(this.id, ksg.ui.BizProcWidgetType.Pager);
	},
	//#

	/**
	* Given a error object from calling a bizrule,t this method will create a message to be
	* given to the ksg.ui.messenger to deal with.
	* Child bizprocs should override this message when they know the bizrules they are calling can return
	* complex error information that needs to be packaged up for presentation to the user.
	* @param {ksg.ErrorInfo} errInfo details about an error that happened, which a message is needed for to display to the user.
	* @returns {String} The message to give to ksg.ui.messenger to display.
	*/
	_getErrorMsg: function(errInfo) {
		var msg = "unknown reason";
		if(errInfo && errInfo.displayText)
			msg = errInfo.displayText();
		else if(errInfo && errInfo.status)
			msg = "Web service failure(" + errInfo.status + "): " + errInfo.statusText + ":<br/>"+ errInfo.responseText;
		return msg;
	},
	
	/**
	* Protected method that does the work to get the bizobj list from where it is supposed to come from.
	* This method is not supposed to decide if its necessary to get the data, it just does the work.
	* @param {function} onSuccess handler that is called after the bizobj list is retrieved successfully.
	*/
	_getBizObjs: function(onSuccess) {
		var self = this;
		
		//If bizobj list is supposed to come from a parent bizproc 
		//(typically a bizobjlist field from the parent's selected bizobj),
		//Get the value from that rather than trying to use a bizrule.
		var depParent = this._getCompletlyDependentParent();
		if(depParent != null) {
			var bizObjs = depParent.getBizObjs();
			if(bizObjs) {
				onSuccess(this._setupBizObjList(bizObjs));
			}
			else {
				//TODO error, cannot get list from dependent parent.
			}
		}
		
		//If we are supposed to get the bizobj list from calling a bizrule, setup the call.
		else if(this.bizRules.getBizObjListBizRule) {
			var onError = function(errInfo) {
				ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.error,"Unable to successfully get bizobj list:<br/>" + self._getErrorMsg(errInfo));
				//todo: process rule call error here.
			};
			var newOnSuccess = function(results) {
				var bizObjs = results.response.bizObjs;
				if(!(bizObjs))
					bizObjs = [];
				onSuccess(self._setupBizObjList(bizObjs));				
			};
			ksg.App.ruleMgr.execute(this.bizRules.getBizObjListBizRule,
									this._getBizObjListRuleParameters(),
									newOnSuccess, onError);
		}
	},
	
	/**
	* Intended to be called only by the _getBizObjs method, this sets up the cursor and flag that we got the data.
	* This could have been an inner method to _getBizObjs but that would make it hard for a child bizproc to override 
	* the behavior here.
	* @param {ksg.bizobj.IBizObjList} bizObjs the bizobjs to use for the source bizobjs in this bizproc.
	*/
	_setupBizObjList: function(bizObjs) {
		if(!(bizObjs))
			bizObjs = [];
		this.bizObjCur = new ksg.bizobj.BizObjCursor(bizObjs);
		if(this.currentBizObjId)
			this._setIndexFromBizObjId(this.currentBizObjId);
		
		this.retrievedBizObjList = true;
		return bizObjs;
	},
	
	/**
	* Internal method that does the work of getting the bizobj details for the bizObjId provided.
	* This method doesnt attempt to decide if its the right time to doe the work, it will always try to:
	* <ol><li>See if it is a completely dependent child of another bizproc and get the bizobj from that</li>
	* <li>If a get detailed bizobj bizrule is provided, call the bizrule to get the details</li>
	* <li>Use the bizobj from the main source bizobj list if it can be found.</li>
	* </ol>
	* @param {Object} bizObjId the id of the bizobj to get the details for
	* @param {function} onSuccess The handler that gets called when the bizrule completes successfully.
	* @param {function} onError The handler that gets called whent he bizrule has an error being called properly.
	* @param {Boolean} isCurrentBizObj if true, this can also setup the currentBizObj for the bizproc
	* when the bizobj is retrieved successfully.
	*/
	_getBizObjDetails: function(bizObjId, onSuccess, onError, isCurrentBizObj) {
		var self = this;
		//If bizobj is supposed to come from a parent bizproc 
		//(typically a bizobj field from the parent's selected bizobj),
		//Get the value from that rather than trying to use a bizrule.
		var depParent = self._getCompletlyDependentParent();
		if(depParent != null) {
			var bizObj = depParent.getBizObj();
			if(bizObj) {
				onSuccess(self._setupCurrentBizObj(bizObj,isCurrentBizObj));
			}
			else {
				//TODO error, cannot get list from dependent parent.
			}
		}
		
		//If we are supposed to get the bizobj list from calling a bizrule, setup the call.
		else if(self.bizRules.getBizObjBizRule) {
			var ruleParams = self._getBizObjDetailRuleParameters(bizObjId);
			if(self._shouldCallGetBizObjDetailsRule.call(self, ruleParams)) {
				var newOnError = function(errInfo) {
					ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.error,"Unable to successfully get bizobj detail:<br/>" + self._getErrorMsg(errInfo));
					//todo: process rule call error here.
					if(onError)
						onError();
				};
				var newOnSuccess = function(results) {
					var bizObj = self._setupCurrentBizObj(results.response,isCurrentBizObj);
					if(onSuccess)
						onSuccess(bizObj);
				};		
				ksg.App.ruleMgr.execute(self.bizRules.getBizObjBizRule, ruleParams,
					newOnSuccess, newOnError);
			}
		}
		else {
			var bizObj = self._getBizObjWithIdFromList(bizObjId);
			if(bizObj != null) {
				bizObj = self._setupCurrentBizObj(bizObj, isCurrentBizObj);
				onSuccess(bizObj);
			}				
		}
		
	},
	
	/**
	* Iterates through the current bizobj list, looking for the first bizobj that has the matching key value.
	* @param {Object} bizObjId a non-null unique identifier for the bizobj desired from the list.
	* @returns {ksg.bizobj.IBizObj} Will return null if there is no matching value
	*/
	_getBizObjWithIdFromList: function(bizObjId) {
		var self = this;
		var bizObj = null;
		if(self.bizObjCur != null)
			for(var i in self.bizObjCur.bizObjs) {
				var child = self.bizObjCur.bizObjs[i];
				if(child[self._keyName] == bizObjId) {
					bizObj = child;
					break;
				}
			}
		return bizObj;
	},
	
	/**
	* Intended to be called only by the _getBizObjDetails method, this sets up the currentBizOBj and flag that we got the data.
	* This could have been an inner method to _getBizObjDetails but that would make it hard for a child bizproc to override 
	* the behavior here.
	* The isCurrentBizObj param is an optional pass boolean that if true will actually just return the bizObj.  This is a helper
	* to reduce the amount of logic needed by _getBizObjDetails when it is used to get details of a bizobj that is not actually
	* being used to set the current bizobj.  That can happenen when outside logic wants to get the details of a bizobj for external use.
	* @param {ksg.bizobj.IBizObj} bizObj The bizobj to be used as the current bizobj.
	* @param {Boolean} isCurrentBizObj this is really a helper parameter for other methods calling this that just want to pass through
	* this method without having to use an if statement to have more complex logic.
	*/
	_setupCurrentBizObj: function(bizObj,isCurrentBizObj) {		
		if(isCurrentBizObj == true) {
			this.currentBizObj = bizObj;
			this.retrievedCurrentBizObj = true;
			if(this.initState == 1)
				this.initState = 2;
			ksg.App.bizProcMgr.bizProcDataAvailable(this, true);
		}
		return bizObj;
	},
	
	/**
	* <p>Will retrieve the current bizobj at the moment. If the bizproc has a getDetailedBizObj bizrule
	* the current bizobj is not already in this.currentBizObj, and onSuccess is passed a function,
	* this method will call the bizrule to get the details, calling onSuccess when the bizrule has
	* completed.</p>
	* <p>If onSuccess is null, this method will not attempt to call the bizrule if the detailed bizobj
	* is unavailable and will return null.
	* If the getDetailedBizObj bizrule is not defined, then the current bizobj will be pulled out of
	* the main list of bizobjs if there is one available.</p>
	* @param {function} onSuccess optional - The handler to call if the bizrule had to be called to get the
	* current bizobj.  However, if provided, this will always be called even if the bizobj is already in memory.
	* @param {function} onError optional - The handler to call if the bizrule had to be called to get
	* the current bizobj but there was an error doing so.
	* @returns the bizobj if available, or null if not currently available.
	*/
	getCurrentBizObj: function(onSuccess, onError) {
	
		var self = this;
		var bizObj = self.inProgressAddBizObj;
		if(!(bizObj)) {
			bizObj = self.currentBizObj;
			if(!self.retrievedCurrentBizObj && onSuccess) {
				self._getBizObjDetails(self.getCurrentBizObjKeyValue(), onSuccess, onError, true);
				return null;
			}
		}
		if(onSuccess)
			onSuccess(bizObj);			

		if(this.initState == 1)
			this.initState = 2;
			
		return bizObj;
	},
	
	/**
	* Will create a new instance of the type of bizobj being used by this bizproc.
	* This is typically used by the addNewBizObj Action.
	* Child bizproc can override this method to control how a new object is created.
	*/
	createNewBizObj: function() {
		return {};
	},
	
	/**
	* Returns an object of parameters to be passed to the bizrule to get the list of bizobjs
	* This is a common method for a child bizproc to override in order to properly gather
	* the parameters needed for the bizrule it is using.
	*/
	_getBizObjListRuleParameters: function() {
	},
	
	/**
	* Returns an object of parameters to be passed to the bizrule to get the details of a given bizobj id.
	* This is a common method for a child bizproc to override in order to properly gather
	* the parameters needed for the bizrule it is using.
	* The default behavior is to return an object with one key/value pair "id" with the id provided.
	* @param {Object} bizObjId The id of the bizobj to get the details for.
	* @returns {Object} A plain object as a Map of parameters to be passed.  This needs to match up
	* to the parameters the get bizobj detail bizrule expects to get.
	*/
	_getBizObjDetailRuleParameters: function(bizObjId) {
		return {id:bizObjId};
	},

	/**
	* Returns an object of parameters to be passed to the bizrule to update a given bizobj.
	* This is a common method for a child bizproc to override in order to properly gather
	* the parameters needed for the bizrule it is using.
	* The default behavior is to return the BizObj that is being updated.
	* @param {ksg.bizobj.IBizObj} bizObj The bizobj being updated
	* @returns {Object} The object of values needed by the given bizrule being used by the bizproc to update the bizobj.
	*/
	_getUpdateBizObjRuleParams: function(bizObj) {
		return bizObj;
	},
	
	/**
	* Returns an object of parameters to be passed to the bizrule to delete a bizobj based on the given id.
	* This is a common method for a child bizproc to override in order to properly gather
	* the parameters needed for the bizrule it is using.
	* The default behavior is to return an object with one key/value pair "id" with the id provided.
	* @param {Object} bizObjId the id of the bizobj to be deleted.
	* @returns {Object} The plain object as a Map of parameters to be passed.
	*/
	_getDeleteBizObjRuleParams: function(bizObjId) {
		return {id:bizObjId};
	},
	
	/**
	* Indicates if the bizproc can decide to use the first bizobj in the list of bizobjs as the selected bizobj
	* when the bizproc is first created and there is no passed id to use.
	* This is intended for a child bizproc to override and control.  Sometimes it is better to not have a selected
	* bizobj until the user specifically picks one and then this should be override to return false.
	* @returns {boolean} 
	*/
	getCanDefaultToFirstInList: function() {
		return true;
	},
	
	/**
	* The parent pizproc relationship id used to get a parent id if needed.
	* This is the standard value of "pid", but under rare situations, it may need to be a different name to 
	* avoid conflicts of some kind.
	* @type String
	*/
	_parentIdKeyName: "pid",
	
	/**
	* Called just before trying to call the bizrule to get the list of bizobjs when they are needed.
	* This method is a good choice for child bizproc to override and control the behavior.
	* If this method returns false, the bizrule will not be called, and the bizproc will behave
	* as if there were no items in the list.
	*/
	_shouldCallGetBizObjListRule: function() {
		var parents = this.parentBizProcs;
		if(parents)
			for(var i in parents)
				if(parents[i].id == this._parentIdKeyName)
					return (parentBizObjId)?true:false;
		return true;		
	},
	
	/**
	* Called just before trying to call the bizrule to get the details of a given bizobj.
	* This method is a good choice for child bizproc to override and control the behavior.
	* If this method returns false, the bizrule will not be called, and the bizproc will behave
	* as if there were no detailed bizobj.
	* @param {Object[]} ruleParams the array of parameters to be passed to the bizrule.
	*/
	_shouldCallGetBizObjDetailsRule: function(ruleParams) {
		var detailDisplays = this._getDetailDisplays();
		return (ruleParams && detailDisplays.length > 0);
	},
	
	/**
	* Called just before trying to call the bizrule to update a given bizobj.
	* This method is a good choice for child bizproc to override and control the behavior.
	* If this method returns false, the bizrule will not be called, and the bizobj will not
	* get updated.
	* @param {Object[]} ruleParams the array of parameters to be passed to the bizrule.
	*/
	_shouldCallUpdateBizObjRule: function(ruleParams) {
		return (ruleParams)?true:false;
	},
	
	/**
	* Called just before trying to call the bizrule to delete a bizobj with the given Id.
	* This method is a good choice for child bizproc to override and control the behavior.
	* If this method returns false, the bizrule will not be called, and the bizobj will not get deleted.
	* @param {Object[]} ruleParams the array of parameters that will be passed to the bizrule 
	*/
	_shouldCallDeleteBizObjRule: function(ruleParams) {
		return (ruleParams)?true:false;		
	},
	
	/**
	* BizProc Action - Will create a new bizobj and put the bizproc into an "add new mode".
	*/
	_addBizObj: function() {
		var newBizObj = this.createNewBizObj();
		var pinfo = this._getCompletlyDependentParent();
		if (pinfo != null) {
			//TODO Properly add new bizobj into parent's bizobj list.
			//SourceBizObjs.Add(newBizObj);
		}		
		
		this.inProgressAddBizObj = newBizObj;
		this._showBizObjDetails();
	},
	
	/**
	* Gets the bizobj that will be modified by the displays to gather the user's updates.
	* This could be the new bizobj if the user is in the add new mode or it could be
	* the current bizobj from calling the get bizobj details bizrule.  If there is not bizrule to
	* get the details, the bizobj from the main list of bizobjs is used.
	* @returns {ksg.bizobj.IBizObj} the bizobj to be updated, should never return null.
	*/
	_getBizObjToUpdate: function() {
		var self = this;
		if(self.options.updateIntoNewBizObj == true)
			return self.createNewBizObj();
		else
			return $.extend({},self.getCurrentBizObj());
	},
	
	/**
	* BizProc Action - Will update the current bizobj via the provided update bizrule.
	*/
	_updateBizObj: function() {
		var self = this;
		var bizObj = self._getBizObjToUpdate();
		var curBizObj = self.getCurrentBizObj();
		var detailDisplays = self._getDetailDisplays();
		if(detailDisplays) {
			for(var i in detailDisplays)
				detailDisplays[i].updateBizObj(bizObj);
			var b = self._getBizObjWithIdFromList(bizObj[self._keyName]);
			if(b != null)
			for(var i in detailDisplays)
				detailDisplays[i].updateBizObj(b);			
		}
		
		var clearShow = function() {
			if(self.options.refreshListOnUpdate)
				self.clearData(true, true, false);
			else if(self.options.updateIntoNewBizObj != true)
				self.clearData(true,false, false);				
			self.showData();
		};
		
		var ruleParams = self._getUpdateBizObjRuleParams(bizObj);
		if(self._shouldCallUpdateBizObjRule(ruleParams)) {
			var onError = function(errInfo) {
				clearShow();
				//TODO process rule call error here.
				ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.error,"Unable to successfully update:<br/>" + self._getErrorMsg(errInfo));
			};
			var onSuccess = function(results) {
				results = self._afterSuccessfulUpdate(results);
				$.extend(curBizObj, bizObj);
				ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.normal,"update successful");
				clearShow();
				//TODO trigger successfull update completed
			};
			ksg.App.ruleMgr.execute(self.bizRules.updateBizRule, ruleParams, onSuccess, onError);
		}
	},
	
	/**
	* Called during the _updateBizObj process, ksg.ui.BizProc calls this to give the child bizproc the chance
	* to modify the results from the bizrule before it is used.
	* @param {Object} results The bizrule return value from updating the bizobj.  The specific details of the
	* results are dependent on the bizrule being called.  This can be null if the bizrule didnt return a value.
	* @returns {Object} The results modified or not.
	*/
	_afterSuccessfulUpdate: function(results) {
		return results;
	},
	
	/**
	* BizProc Action - Will delete the currently selected bizobj.
	*/
	_deleteCurrentBizObj: function() {
		var self = this;
		var bizObjId = self.getCurrentBizObjKeyValue();
		if(self.bizRules.deleteBizRule) {
			var ruleParams = self._getDeleteBizObjRuleParams(bizObjId, self.getCurrentBizObj());
			if(self._shouldCallDeleteBizObjRule(ruleParams)) {
				var onError = function(errInfo) {
					ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.error,"Error while trying to delete bizobj:<br/>" + self._getErrorMsg(errInfo));
				};
				var onSuccess = function(results) {
					ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.normal,"delete successful");
					var bizObjs = self.getSourceBizObjs();
					for(var i = 0; i < bizObjs.length; i++)
						if(bizObjs[i][self._keyName] == bizObjId) {
							bizObjs.splice(i,1);
							self.bizObjCur = new ksg.bizobj.BizObjCursor(bizObjs);
							if(i >=bizObjs.length)
								i = bizObjs.length -1;
							if(i >= 0) {
								self.selectBizObj(bizObjs[i][self._keyName]);								
								self.showData();
							}
								
							break;
						}
				};
				ksg.App.ruleMgr.execute(self.bizRules.deleteBizRule, ruleParams, onSuccess, onError);			
			}
		}
	},
	
	/**
	* BizProc Action - Will cancel any edits made by the user and revert back. 
	* This is typically only shown when in "add mode" and will cancel the new bizobj and go back to showing the 
	* currently selected bizobj.
	*/
	_cancelEdits: function() {
		this._internalCancelEdits();
		this.inProgressAddBizObj = null;
		this.showData();
	},
	
	/**
	* Called by _cancelEdits, this is an easy method for child bizprocs to override in order
	* to do something as a part of _cancelEdits without having to override that method
	* and deal with ensureing the base functionality was called.  
	* <p>This method has no behavior in this class and if overriden by a child, the child doesnt need to 
	* call this method back.</p>
	*/
	_internalCancelEdits: function() {
		//Intentionally left blank.  This is specifically for child bizprocs to override
	},
	
	/**
	* BizProc Action - Will toggle the bizproc's edit mode, if it is using one.
	*/
	_switchEditMode: function() {
		var editModeKey = this.options.editModeSessionKey;
		var txt = editModeKey?ksg.App.SessionData()[editModeKey]:"always on editing";
		this._internalSwitchEditMode();
		if(this.options.refreshListOnEditToggle)
			this.clearData(true,true,false);
		this.showData();
	},
	
	/**
	* Called by _switchEditMode, this is an easy method for child bizprocs to override in order
	* to do something as a part of _swtichEditMode without having to override that method
	* and deal with ensureing the base functionality was called.  
	* <p>This method has no behavior in this class and if overriden by a child, the child doesnt need to 
	* call this method back.</p>
	*/
	_internalSwitchEditMode: function() {
		//Intentionally left blank.  This is specifically for child bizprocs to override
	},

	//#Indexing Support ---
	/**
	* BizProc Action - Will change the current bizobj to the first bizobj in the list.
	*/
	_moveFirst: function() {
		this._selCur(this.bizObjCur.moveFirst());
	},
	/**
	* BizProc Action - Will change the current bizobj to the previous bizobj in the list based on the current bizobj position.
	*/
	_movePrev: function() {
		this._selCur(this.bizObjCur.movePrev());
		ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.normal,"moved to previous item.");
	},
	/**
	* BizProc Action - Will change the current bizobj to the next bizobj in the list based on the current bizobj position.
	*/
	_moveNext: function() {
		this._selCur(this.bizObjCur.moveNext());
		ksg.ui.messenger.displayMessage(ksg.ui.messenger.levels.normal,"moved to next item.");
	},
	/**
	* BizProc Action - Will change the current bizobj to the last bizobj in the list.
	*/
	_moveLast: function() {
		this._selCur(this.bizObjCur.moveLast());
	},

	/**
	* Drives the internal ksg.bizobj.BizObjCursor to the specific index location of the bizObj
	* that was selected.
	* @param {ksg.bizobj.IBizObj} bizObj the bizobj to select based on the index cursor
	* being moved.
	*/
	_selCur: function(bizObj) {
		this.selectBizObj(bizObj[this._keyName], true);
	}
	//#
	
}
